import { WebSocketGateway, SubscribeMessage, MessageBody, WebSocketServer, OnGatewayConnection, OnGatewayDisconnect, ConnectedSocket } from '@nestjs/websockets';
import { Server, Socket } from 'socket.io'
import { ChatService } from './chat.service';
import { CreateChatDto } from './dto/create-chat.dto';
import { UpdateChatDto } from './dto/update-chat.dto';
import { FriendMessage, Group, GroupMap, GroupMessage, Prisma, User, UserMap } from '@prisma/client';
import { PrismaService } from 'src/prisma.service';
import { CODE } from 'src/common/base';
import { nameVerify } from 'src/common/util/verify';
import { createWriteStream } from 'fs';
import { join } from 'path';
var dayjs = require('dayjs')

@WebSocketGateway(8889, {
  transports: ['websocket'],
  cors: {
    origin: '*'
  }
})
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
  constructor(
    private prisma: PrismaService,
    private readonly chatService: ChatService
  ) {
    this.defaultGroup = '默认聊天室'
  }

  @WebSocketServer()
  server: Server

  // 默认群
  defaultGroup: string;

  // socket 连接
  handleConnection(client: Socket, ...args: any[]) {
    const userRoom = client.handshake.query.userId
    console.log('userRoom', userRoom)

    // 用户独有房间
    if (userRoom) {
      client.join(userRoom)
    } else { // 默认房间
      client.join(this.defaultGroup)
    }

    // 统计在线人数
    // this.getActiveGroupUser()
  }

  handleDisconnect(client: any) {
    // throw new Error('Method not implemented.');
  }

  // 加入私聊的socket连接
  @SubscribeMessage('joinFriendSocket')
  async joinFriend(@ConnectedSocket() client: Socket, @MessageBody() data: UserMap): Promise<any> {
    if (data.friendId && data.userId) {
      const relation = await this.chatService.queryUserMap({ userId: data.userId, friendId: data.friendId });
      const roomId = data.userId > data.friendId ? data.userId + data.friendId : data.friendId + data.userId;
      if (relation) {
        client.join(roomId);
        this.server.to(data.userId).emit('joinFriendSocket', { code: CODE.SUCCESS, msg: '进入私聊socket成功', data: relation });
      }
    }
  }

  // 加入群组的socket连接
  @SubscribeMessage('joinGroupSocket')
  async joinGroupSocket(@ConnectedSocket() client: Socket, @MessageBody() data: GroupMap): Promise<any> {
    const group = await this.chatService.queryGroup({ groupId: data.groupId });
    const user = await this.chatService.queryUser({ userId: data.userId });
    if (group && user) {
      client.join(group.groupId);
      const res = { group: group, user: user };
      this.server.to(group.groupId).emit('joinGroupSocket', { code: CODE.SUCCESS, msg: `${user.username}加入群${group.groupName}`, data: res });
    } else {
      this.server.to(data.userId).emit('joinGroupSocket', { code: CODE.PARAMERROR, msg: '进群失败', data: '' });
    }
  }

  // 创建群组
  @SubscribeMessage('addGroup')
  async addGroup(@ConnectedSocket() client: Socket, @MessageBody() data: Group) {
    // 查询用户是否存在
    const isUser = await this.chatService.queryUser({ userId: data.userId })
    if (isUser) {
      // 判断群组是否存在
      const isHave = await this.chatService.queryGroup({ groupName: data.groupName })
      if (isHave) {
        console.log('isHave', isHave, data.userId,)
        this.server.to(data.userId).emit('addGroup', { code: CODE.DATAESIST, msg: '该群名字已存在', data: isHave });
        return;
      }
      // 验证群组名字
      if (!nameVerify(data.groupName)) {
        return;
      }

      // 创建
      data = await this.chatService.createGroup(data)
      client.join(data.groupId)

      // 添加 用户 和 群组的关联关系
      const group = await this.chatService.createGroupMap({ groupId: data.groupId, userId: data.userId })
      this.server.to(group.groupId).emit('addGroup', { code: CODE.SUCCESS, msg: `成功创建群${data.groupName}`, data: group });
      // this.getActiveGroupUser();
    } else {
      this.server.to(data.userId).emit('addGroup', { code: CODE.NOAUTH, msg: `你没资格创建群` });
    }
  }

  // 加入群组
  @SubscribeMessage('userJoinGroup')
  async userJoinGroup(@ConnectedSocket() client: Socket, @MessageBody() data: GroupMap) {
    // 是否是一个已注册用户
    const user = await this.chatService.queryUser({ userId: data.userId })
    if (user) {
      // 查询是否存在群组
      const group = await this.chatService.queryGroup({ groupId: data.groupId })
      // 是否已加入群组
      let userGroup = await this.chatService.queryGroupMap({ groupId: data.groupId, userId: data.userId })
      if (group) {
        if (!userGroup) {
          // 进入群组
          userGroup = await this.chatService.createGroupMap({ userId: data.userId, groupId: data.groupId })
        }
        client.join(group.groupId);
        const res = { group: group, user: user };
        this.server.to(group.groupId).emit('userJoinGroup', {
          code: CODE.SUCCESS,
          msg: `${user.username}加入群${group.groupName}`,
          data: res
        });
        // this.getActiveGroupUser();
      } else {
        this.server.to(data.userId).emit('userJoinGroup', { code: CODE.SQLERROR, msg: '进群失败', data: '' });
      }
    } else {
      this.server.to(data.userId).emit('userJoinGroup', { code: CODE.NOAUTH, msg: '你没资格进群' });
    }
  }

  // 多人加入群聊
  @SubscribeMessage('usersJoinGroup')
  async usersJoinGroup(@ConnectedSocket() client: Socket, @MessageBody() data: { userId: UserMap['userId'], friendIdList: UserMap['friendId'][], groupId: string }) {
    // 查询用户是否存在
    const isUser = await this.chatService.queryUser({ userId: data.userId })
    if (isUser) {
      // 判断群组是否存在
      const group = await this.chatService.queryGroup({ groupId: data.groupId })
      if (!group) {
        console.log('isHave', group, data.userId,)
        this.server.to(data.userId).emit('usersJoinGroup', { code: CODE.DATAESIST, msg: '该群不存在', data: group });
        return;
      }

      const list = data.friendIdList.map(item => ({ userId: item, groupId: data.groupId }))
      const count = await this.chatService.createGroupMapMany(list)

      // 查询用户名
      const usernameList = await this.chatService.queryUsernameByUserIds(data.friendIdList)
      // 添加群系统消息
      const groupMessage: Prisma.GroupMessageCreateInput = {
        userId: data.userId,
        groupId: data.groupId,
        content: usernameList.join(', ') + '进入群聊！',
        creator: 'SYSTEM',
        messageType: 'text',
      }

      await this.chatService.createGroupMessage(groupMessage)

      client.join(group.groupId);
      const res = { group: group, count: count };
      this.server.to(group.groupId).emit('usersJoinGroup', {
        code: CODE.SUCCESS,
        msg: usernameList.join(', ') + '进入群聊！',
        data: res
      });

      // this.getActiveGroupUser();
    } else {
      this.server.to(data.userId).emit('usersJoinGroup', { code: CODE.NOAUTH, msg: `你没资格拉人进群` });
    }
  }

  // 创建群组并入群
  @SubscribeMessage('add-join-group')
  async addJoinGroup(@ConnectedSocket() client: Socket, @MessageBody() data: { userId: UserMap['userId'], friendIdList: UserMap['friendId'][], groupConfig: { groupName: string, avatar: string } }) {
    // 查询用户是否存在
    const isUser = await this.chatService.queryUser({ userId: data.userId })
    if (isUser) {
      // 判断群组是否存在
      const isHave = await this.chatService.queryGroup({ groupName: data.groupConfig.groupName })
      if (isHave) {
        console.log('isHave', isHave, data.userId,)
        this.server.to(data.userId).emit('add-join-group', { code: CODE.DATAESIST, msg: '该群名字已存在', data: isHave });
        return;
      }
      // 验证群组名字
      if (!nameVerify(data.groupConfig.groupName)) {
        this.server.to(data.userId).emit('add-join-group', { code: CODE.PARAMERROR, msg: '群组名称不合法', data: '' });
        return;
      }

      // 创建
      const groupRes = await this.chatService.createGroup({ userId: data.userId, groupName: data.groupConfig.groupName, avatar: data.groupConfig.avatar })
      client.join(groupRes.groupId)

      // 添加 用户 和 群组的关联关系
      const group = await this.chatService.createGroupMap({ groupId: groupRes.groupId, userId: data.userId })
      this.server.to(group.groupId).emit('add-join-group', { code: CODE.SUCCESS, msg: `成功创建群${data.groupConfig.groupName}`, data: group });

      if (group) {
        const list = data.friendIdList.map(item => ({ userId: item, groupId: groupRes.groupId }))
        const count = await this.chatService.createGroupMapMany(list)

        // 查询用户名
        const usernameList = await this.chatService.queryUsernameByUserIds(data.friendIdList)
        // 添加群系统消息
        const groupMessage: Prisma.GroupMessageCreateInput = {
          userId: data.userId,
          groupId: groupRes.groupId,
          content: '群组成员有：' + usernameList.join(', '),
          creator: 'SYSTEM',
          messageType: 'text',
        }

        await this.chatService.createGroupMessage(groupMessage)

        client.join(group.groupId);
        const res = { group: group, count: count };
        this.server.to(group.groupId).emit('add-join-group', {
          code: CODE.SUCCESS,
          msg: `群 ${groupRes.groupName} 添加成员成功 ～`,
          data: res
        });
        // this.getActiveGroupUser();
      } else {
        this.server.to(data.userId).emit('add-join-group', { code: CODE.SQLERROR, msg: '进群失败', data: '' });
      }

      // this.getActiveGroupUser();
    } else {
      this.server.to(data.userId).emit('add-join-group', { code: CODE.NOAUTH, msg: `你没资格创建群` });
    }
  }

  // 发送群消息
  @SubscribeMessage('groupMessage')
  async groupMessage(@MessageBody() data: GroupMessage) {
    const user = await this.chatService.queryUser({ userId: data.userId })
    if (user) {
      // 用户是否在某个群组中
      const userGroup = await this.chatService.queryGroupMap({ userId: data.userId, groupId: data.groupId })
      if (!userGroup || !data.groupId) {
        this.server.to(data.userId).emit('groupMessage', { code: CODE.PARAMERROR, msg: '群消息发送错误', data: '' });
        return;
      }
      if (data.messageType === 'image') {
        const randomName = `${Date.now()}$${data.userId}`;
        const stream = createWriteStream(join('public/static', randomName));
        stream.write(data.content);
        data.content = randomName;
      }

      data = await this.chatService.createGroupMessage(data);
      this.server.to(data.groupId).emit('groupMessage', { code: CODE.SUCCESS, msg: '', data: data });
    } else {
      this.server.to(data.userId).emit('groupMessage', { code: CODE.NOAUTH, msg: '你没资格发消息' });
    }
  }

  // 添加好友
  @SubscribeMessage('addFriend')
  async addFriend(@ConnectedSocket() client: Socket, @MessageBody() data: UserMap) {
    const user = await this.chatService.queryUser({ userId: data.userId })
    // 想要添加的用户是否存在
    const friend = await this.chatService.queryUser({ userId: data.friendId })
    if (user && friend) {
      // 用户和某个用户是否是朋友
      const userGroup = await this.chatService.queryUserMap({ userId: data.userId, friendId: data.friendId })
      if (userGroup) {
        this.server.to(data.userId).emit('addFriend', { code: CODE.PARAMERROR, msg: '你和该用户已是好友', data: '' });
        return;
      }
      // 添加好友
      await this.chatService.createUserMap({ userId: data.userId, friendId: data.friendId })
      await this.chatService.createUserMap({ userId: data.friendId, friendId: data.userId })
      // 系统添加消息提示
      const userMessage: Prisma.FriendMessageCreateInput = {
        userId: data.userId,
        friendId: data.friendId,
        content: '添加好友' + friend.username + '成功！',
        creator: 'SYSTEM',
        messageType: 'text',
      }

      const friendMessage: Prisma.FriendMessageCreateInput = {
        userId: data.friendId,
        friendId: data.userId,
        content: '你和' + user.username + '已经成为好友！',
        creator: 'SYSTEM',
        messageType: 'text',
      }

      // 存入数据库
      await this.chatService.createUserMessage(userMessage)
      await this.chatService.createUserMessage(friendMessage)
      this.server.to(data.userId).emit('addFriend', { code: CODE.SUCCESS, msg: '添加好友成功', data: friend });
      //  this.server.to(data.friendId).emit('addFriend', { code: CODE.SUCCESS, msg: '', data: user });
    } else {
      this.server.to(data.userId).emit('addFriend', { code: CODE.NOAUTH, msg: '用户或朋友不存在' });
    }
  }

  // 发送私聊消息
  @SubscribeMessage('friendMessage')
  async friendMessage(@MessageBody() data: FriendMessage) {
    const user = await this.chatService.queryUser({ userId: data.userId })
    if (user) {
      // 用户和某个用户是否是朋友
      const userGroup = await this.chatService.queryUserMap({ userId: data.userId, friendId: data.friendId })
      if (!userGroup || !data.friendId) {
        this.server.to(data.userId).emit('friendMessage', { code: CODE.PARAMERROR, msg: '私聊消息发送错误', data: '' });
        return;
      }
      if (data.messageType === 'image') {
        const randomName = `${Date.now()}$${data.userId}`;
        const stream = createWriteStream(join('public/static', randomName));
        stream.write(data.content);
        data.content = randomName;
      }

      data = await this.chatService.createUserMessage(data);
      this.server.to(data.userId).emit('friendMessage', { code: CODE.SUCCESS, msg: '', data: data });
      this.server.to(data.friendId).emit('friendMessage', { code: CODE.SUCCESS, msg: '', data: data });
    } else {
      this.server.to(data.userId).emit('friendMessage', { code: CODE.NOAUTH, msg: '你没资格发消息' });
    }
  }

  // 获取和朋友的聊天记录
  @SubscribeMessage('getFriendMessage')
  async getFriendMessage(@ConnectedSocket() client: Socket, @MessageBody() data: UserMap) {
    const user = await this.chatService.queryUser({ userId: data.userId })
    if (user) {
      // 用户和某个用户是否是朋友
      const userGroup = await this.chatService.queryUserMap({ userId: data.userId, friendId: data.friendId })
      if (!userGroup || !data.friendId) {
        this.server.to(data.userId).emit('getFriendMessage', { code: CODE.PARAMERROR, msg: '你和当前用户不是好友关系', data: '' });
        return;
      }

      // 发给朋友的消息
      // const toFriendMessage = await this.chatService.queryFriendMessage({
      //   where: { userId: data.userId, friendId: data.friendId },
      //   take: 30,
      //   orderBy: { createTime: 'asc' },
      // })


      // // 接收到的朋友的消息
      // const exceptFriendMessage = await this.chatService.queryFriendMessage({
      //   where: { friendId: data.userId, userId: data.friendId },
      //   take: 30,
      //   orderBy: { createTime: 'asc' },
      // })
      // this.server.to(data.userId).emit('getFriendMessage', { code: CODE.SUCCESS, msg: '获取私聊数据', data: {
      //   toFriendMessage,
      //   exceptFriendMessage
      // } });
      const friendMessage = await this.chatService.queryFriendMessage({
        where: {
          OR: [
            { userId: data.userId, friendId: data.friendId },
            { friendId: data.userId, userId: data.friendId }
          ]
        },
        take: 30,
        orderBy: { createTime: 'desc' },
      })
      this.server.to(data.userId).emit('getFriendMessage', { code: CODE.SUCCESS, msg: '获取私聊数据', data: friendMessage.reverse() });
    } else {

    }
  }

  // 获取群组的聊天记录
  @SubscribeMessage('getGroupMessage')
  async getGroupMessage(@ConnectedSocket() client: Socket, @MessageBody() data: GroupMap) {
    const user = await this.chatService.queryUser({ userId: data.userId })

    if (user) {
      // 用户和某个用户是否是朋友
      const userGroup = await this.chatService.queryGroupMap({ userId: data.userId, groupId: data.groupId })
      if (!userGroup || !data.groupId) {
        this.server.to(data.userId).emit('getGroupMessage', { code: CODE.PARAMERROR, msg: '你不属于当前群组', data: '' });
        return;
      }
      const userMap = {}
      //
      const groupMessages = await this.chatService.queryGroupMessage({
        orderBy: {
          createTime: 'desc'
        },
        where: {
          groupId: data.groupId
        },
        take: 30
      })
      // 查找是那个用户发送的消息
      for (const item of groupMessages) {
        // 如果当前message对应的用户已经查过不需要在查
        if (!userMap[item.userId]) {
          const user = await this.chatService.queryUser({ userId: item.userId })
          userMap[item.userId] = user
        }
      }

      console.log('*******', groupMessages, userMap)
      this.server.to(data.groupId).emit('getGroupMessage', {
        code: CODE.SUCCESS, msg: '获取群组聊天数据成功', data: {
          groupMessages: groupMessages.reverse(),
          userData: userMap
        }
      });
    } else {

    }
  }

  // 获取所有群和用户数据
  @SubscribeMessage('chatData')
  async getAllData(@ConnectedSocket() client: Socket, @MessageBody() data: User) {
    const user = await this.chatService.queryUser({ userId: data.userId })
    if (user) {
      // 根据用户 查询 加入的群组 Map
      const userGroup = await this.chatService.queryGroupMapList({ userId: data.userId })
      // 根据用户 查询 的好友 map
      const userFriend = await this.chatService.queryUserMapList({ userId: data.userId })

      // 获取所有的群组
      const groupsPromise = userGroup.map(async (item) => {
        return await this.chatService.queryGroup({ groupId: item.groupId })
      })

      //获取所有的朋友数据
      const friendsPromise = userFriend.map(async (item) => {
        return await this.chatService.queryUser({ userId: item.friendId })
      })


      type TGroup = Group & { messages?: GroupMessage[] }
      const groups: TGroup[] = await Promise.all(groupsPromise)
      // 将群消息插入对应的群数据中
      const newGroups = groups.sort((a, b) => (dayjs(b.createTime).unix() - dayjs(a.createTime).unix())).map(async (group, index) => {
        const groupMessage = await this.chatService.queryGroupMessage({
          orderBy: {
            createTime: 'desc'
          },
          where: {
            groupId: group.groupId
          },
          take: 1
        })
        group.messages = groupMessage;
        return group
      })

      type TFriend = User & { messages?: FriendMessage[] }
      const friends: TFriend[] = await Promise.all(friendsPromise)

      const newFriends = friends.sort((a, b) => (dayjs(b.createTime).unix() - dayjs(a.createTime).unix())).map(async (friend, index) => {
        // 获取和当前朋友的最新一条消息
        const friendMessage = await this.chatService.queryFriendMessage({
          orderBy: {
            createTime: 'desc'
          },
          where: {
            OR: [
              { userId: user.userId, friendId: friend.userId },
              { friendId: user.userId, userId: friend.userId }
            ]
          },
          take: 1 // 查找有一条用于展示，朋友列表的最新消息
        })
        friend.messages = friendMessage;
        return friend
      });


      this.server.to(user.userId).emit('chatData', {
        code: CODE.SUCCESS, msg: '获取聊天数据成功', data: {
          groupData: await Promise.all(newGroups),
          friendData: await Promise.all(newFriends),
          // userData: [...friends]
        }
      });
    } else {

    }
  }

  @SubscribeMessage('removeChat')
  remove(@MessageBody() id: number) {
    // return this.chatService.remove(id);
  }

  // 退群
  @SubscribeMessage('existGroup')
  async existGroup(@ConnectedSocket() client: Socket, @MessageBody() data: GroupMap) {
    const user = await this.chatService.queryUser({ userId: data.userId })
    const group = await this.chatService.queryGroup({ groupId: data.groupId })
    const groupMap = await this.chatService.queryGroupMap({ userId: data.userId, groupId: data.groupId })

    if (user && group && groupMap) {
      const res = await this.chatService.removeGroupMap({
        where: { id: groupMap.id }
      })

      // 添加群系统消息
      const groupMessage: Prisma.GroupMessageCreateInput = {
        userId: data.userId,
        groupId: data.groupId,
        content: user.username + '退出群聊！',
        creator: 'SYSTEM',
        messageType: 'text',
      }

      const exitMsg = await this.chatService.createGroupMessage(groupMessage)

      // client.join(group.groupId);
      this.server.to(group.groupId).emit('existGroup', {
        code: CODE.SUCCESS,
        msg: groupMessage.content,
        data: exitMsg
      });

    } else {
      this.server.to(data.groupId).emit('existGroup', { code: CODE.NOAUTH, msg: '退群失败' });
    }
  }

  // 删除好友
  @SubscribeMessage('existFriend')
  async existFriend(@MessageBody() data: UserMap) {
    const user = await this.chatService.queryUser({ userId: data.userId })
    const map1 = await this.chatService.queryUserMap({ userId: data.userId, friendId: data.friendId })
    const map2 = await this.chatService.queryUserMap({ userId: data.friendId, friendId: data.userId })
    if (user && map1 && map2) {
      await this.chatService.removeUserMap({ where: { id: map1.id }})
      await this.chatService.removeUserMap({ where: { id: map2.id }})
      this.server.to(data.userId).emit('existFriend', { code: CODE.SUCCESS, msg: '删除好友成功' });
      return
    }
    this.server.to(data.userId).emit('existFriend', { code: CODE.FAIL, msg: '删除好友失败' });

  }

  getActiveGroupUser() {
    // @ts-ignore;
    let userIdArr = Object.values(this.server.engine.clients).map(item => {
      // @ts-ignore;
      return item.request._query.userId;
    });
    // console.log(userIdArr)
  }
}
